using System;
using System.Linq.Expressions;
using System.Reflection;
using NUnit.Framework;

namespace Charisma.Tests
{
  [TestFixture]
  public class ReflectionTests
  {
    internal class Target
    {
      public T GenericMethod<T>(T value)
      {
        return value;
      }

      public string RegularMethod(string value)
      {
        return value;
      }
    }

    public struct S
    {
      public int Id { get; set; }

      public static object GetId(S s)
      {
        return s.Id;
      }

      public static void SetId(S s, object v)
      {
        s.Id = (int) v;
      }
    }

    public class C
    {
      public int Id { get; set; }

      public static object GetId(C c)
      {
        return c.Id;
      }

      public static void SetId(C c, object v)
      {
        c.Id = (int) v;
      }
    }

    [Test]
    public void CreateDelegateToGenericMethod()
    {
      string result;
      var target = new Target();
      Func<string, string> f = target.GenericMethod;
      result = f.Invoke("value");
      Assert.AreEqual("value", result);

      result = null;
      var instance = Expression.Parameter(typeof (Target), "instance");
      var argument = Expression.Parameter(typeof(string), "argument");
      var rmc = Expression.Call(instance, "RegularMethod", null, argument);
      var r = Expression.Lambda<Func<Target, string, string>>(rmc, instance, argument).Compile();
      result = r(target, "value");
      Assert.AreEqual("value", result);

      result = null;
      var gmc = Expression.Call(instance, "GenericMethod", new[] {typeof (string)}, argument);
      var g = Expression.Lambda<Func<Target, string, string>>(gmc, instance, argument).Compile();
      result = g(target, "value");
      Assert.AreEqual("value", result);
    }
  }
}